package com.lucene.service;

import com.hankcs.lucene.HanLPAnalyzer;
import com.lucene.analyzer.CustomizedAnalyzer;
import com.lucene.mapper.ProjectMapper;
import com.lucene.model.Project;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.*;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.*;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zhangzhen on 22/09/2017.
 *
 * 主要包括以下功能:
 * 1、首次开启服务为数据库所有数据构建索引
 * 2、提供页面添加构建索引服务
 * 3、提供检索功能
 */
@Service("luceneService")
public class LuceneService {

    private static Logger logger = Logger.getLogger(LuceneService.class);

    @Autowired
    private ProjectMapper projectMapper;

    private Analyzer analyzer;

    private static final String INDEX_DIRECTORY = "index";// 索引存储位置

    private Directory index;// 文件索引

    public LuceneService() throws IOException{
        //  this.index = new RAMDirectory();
        this.index  = FSDirectory.open(Paths.get(INDEX_DIRECTORY));
        this.analyzer = new CustomizedAnalyzer("dict/stopwords.txt","dict/user.dict",true);
    }

    private void addDoc(IndexWriter w, Project p) throws IOException {
        Document doc = new Document();
        doc.add(new StringField("key", p.getKey(), Field.Store.YES));
        doc.add(new StringField("name", p.getName(), Field.Store.YES));
        doc.add(new StringField("reporter", p.getReporter(), Field.Store.YES));
        doc.add(new StringField("supporter", p.getSupporter(), Field.Store.YES));
        doc.add(new StringField("summary", p.getSummary(), Field.Store.YES));
        doc.add(new StringField("scheme", p.getScheme(), Field.Store.YES));
        doc.add(new TextField("description", p.getDescription(), Field.Store.YES));

        Term id =new Term("key", p.getKey());
        w.updateDocument(id, doc);
    }

    public int addOneItemIndex(Project project) throws IOException{

        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        IndexWriter w = new IndexWriter(this.index, config);
        addDoc(w, project);
        w.commit();
        w.close();
        return 0;
    }
    public int deleteAllIndex() throws IOException{

        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        IndexWriter w = new IndexWriter(this.index, config);
        w.deleteAll();
        w.commit();
        w.close();
        return 0;
    }
    public int initDBItemIndex() throws IOException{
        /**
         * 初始化数据库全文件索引
         */
        // indexWriter的配置信息
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        // 获取所有项目
        List<Project> projects = projectMapper.getAllProjects();
        if (projects!=null && projects.size() > 0){
            IndexWriter w = new IndexWriter(this.index, config);
            // 初始化先清空索引
            // w.deleteAll();
            for(Project p : projects){
                addDoc(w, p);
            }
            w.commit();
            w.close();
        }
        return 0;
    }

    public void showIndexNums() throws IOException{
        IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(this.index));
        Query query = new MatchAllDocsQuery();
        int nums = searcher.count(query);
        logger.info("total num: "+nums);
    }
    public List<Project> searchProject(String queryStr){

        IndexReader reader = null;
        IndexSearcher searcher = null;
        List<Project> rs = null;
        try {
            Query q = new QueryParser("description", this.analyzer).parse(queryStr);
            int hitsPerPage = 3;
            reader = DirectoryReader.open(this.index);
            searcher = new IndexSearcher(reader);
            TopScoreDocCollector collector = TopScoreDocCollector.create(hitsPerPage);
            searcher.search(q, collector);
            searcher.explain(q,hitsPerPage);
            TopDocs topDocs = collector.topDocs();
            ScoreDoc[] socreDocs = topDocs.scoreDocs;

            rs = new ArrayList<>();
            for (ScoreDoc sd: socreDocs) {
                Document document = searcher.doc(sd.doc);
                Explanation explanation = searcher.explain(q, sd.doc);
                logger.info(explanation.toString());


                String key = document.get("key");
                String name = document.get("name");
                String reporter = document.get("reporter");
                String supporter = document.get("supporter");
                String summary = document.get("summary");
                String scheme = document.get("scheme");
                String description = document.get("description");

                Project p = new Project(key, name, reporter, supporter, summary, scheme, description);
                p.setScore(sd.score);
                rs.add(p);
            }
            return rs;

        }catch (ParseException pe){
            logger.error("ParseEx "+pe.getMessage());
        }catch (IOException ie){
            logger.error("IOEx "+ie.getMessage());
        }finally {
            try {
                if (reader!=null)
                    reader.close();
            }catch (IOException e){
                logger.error("IOEx "+e.getMessage());
            }
        }
        return null;
    }
}
